//! 应用程序控制模块

use std::collections::HashMap;

use crate::Parser;
use file_sql::ForceUnwrap;

trait RemoveQuote {
    fn remove_quote(self) -> String;
}

impl RemoveQuote for String {
    /// 去除引号
    fn remove_quote(self) -> String {
        if self.starts_with("\"") && self.ends_with("\"") {
            return self[1..self.len() - 1].to_string();
        }

        self
    }
}

/// 单个服务配置信息
#[derive(Debug, Clone)]
pub struct Service {
    pub name: String,
    pub file: String,
    pub url: String,
    pub desp: String,
}
impl Service {
    pub fn from_map(index: usize, map: &HashMap<String, Option<String>>) -> Self {
        let name = map
            .get("name")
            .and_then(|s| s.clone())
            .or(Some(format!("service.{}", index)))
            .force_unwrap()
            .remove_quote();

        let desp = map
            .get("desp")
            .and_then(|s| s.clone())
            .or(Some(format!("no description")))
            .force_unwrap()
            .remove_quote();
        let file = map
            .get("file")
            .and_then(|s| s.clone())
            .force_unwrap()
            .remove_quote();
        let url = map
            .get("url")
            .and_then(|s| s.clone())
            .force_unwrap()
            .remove_quote();
        Self {
            name,
            file,
            url,
            desp,
        }
    }
}

/// 应用程序控制器
#[derive(Debug, Clone)]
pub struct App {
    pub dir: String,
    pub port: String,
    pub path: String,
    pub title: String,
    pub sub_title: String,
    pub table_heads: Vec<String>,
    pub services: Vec<Service>,
}

impl App {
    /// 从文件中加载控制器
    pub fn from_file(path: &str) -> Self {
        Self::from(Parser::from_file(path))
    }

    /// 命令行加载控制器
    pub fn parse_env() -> Self {
        let path = if let Some(input) = std::env::args().nth(1) {
            format!("{}/{}", std::env::current_dir().unwrap().display(), input)
        } else {
            format!("{}/fql.ini", std::env::current_dir().unwrap().display())
        };

        if !std::path::Path::new(&path).exists() {
            println!("Config file [\"{}\"] load failed", path);
            std::process::exit(0);
        }

        Self::from_file(&path)
    }

    /// 返回在本地运行地址
    pub fn localhost(&self) -> String {
        format!("localhost:{}", self.port)
    }
}

impl From<Parser<'_>> for App {
    fn from(parser: Parser<'_>) -> Self {
        let port = parser
            .get_value("main/port", "4000".to_string())
            .remove_quote();

        let title = parser
            .get_value("main/title", "FQLServer".to_string())
            .remove_quote();

        let sub_title = parser
            .get_value("main/subtitle", "welcome to index page".to_string())
            .remove_quote();

        let mut index = 0;
        let mut services = Vec::new();
        while let Some(map) = parser.value.get(&format!("service.{}", index)) {
            services.push(Service::from_map(index, map));
            index += 1;
        }

        let file = std::path::Path::new(parser.path.unwrap());
        let dir = file.parent().unwrap().to_str().unwrap().to_string();

        let table_heads = vec![
            parser
                .get_value("main/name", "Name".to_string())
                .remove_quote(),
            parser
                .get_value("main/url", "URL".to_string())
                .remove_quote(),
            parser
                .get_value("main/desp", "Description".to_string())
                .remove_quote(),
            parser
                .get_value("main/file", "File".to_string())
                .remove_quote(),
        ];

        Self {
            dir,
            title,
            sub_title,
            table_heads,
            port,
            services,
            path: parser.path.unwrap().to_string(),
        }
    }
}

#[cfg(test)]
mod test {

    use crate::*;
    #[test]
    fn test_app() {
        let app = App::from_file("examples/fql.server.ini");
        println!("{:#?}", app);
    }
}
